#ifndef MCREUSE_H
#define MCREUSE_H
#include <vector>
#include <boost/multi_array.hpp>
#include <iostream>
#include <string>
#include <fstream>
#include <ctime>
#include <boost/timer.hpp>
#include "MCreuse.h"

using namespace boost;
using namespace std;

template <typename T>
class MCreuse
{
	private :
	//nouveaux attribus
	boost::multi_array<int,2> Indices;
	vector <T> Values;
	int lignes_;
	
	public:
	//constructeur et destructeur
	MCreuse();
	MCreuse(int nb_lignes);
	//~MCreuse();
	//methode 
	void readMCreuse();
	void printIndices();
	void printValues();
	void AjoutElements(T k, int i, int j);
	//produit matrice/vecteur
	void SPMV(const vector <T>& u, vector <T> v);
 };
 
 /****************************************************************************
    * Fonction: MCreuse<T>::MCreuse()
    * Description: Constructeur par defaut
    * Paramètres: aucun
    * Retour: aucun
    ****************************************************************************/
    template <typename T>
    MCreuse<T>::MCreuse()
   {
	   Indices.resize(boost::extents[lignes_][2]);
	   for(int i=0;i<lignes_;i++)
	   {
		   for(int j=0;j<2;j++)
		   {
			   Indices[i][j]=i;
		   }
		   Values.push_back(1);
	   }   
   }
  /****************************************************************************
    * Fonction: MCreuse<T>::MCreuse()
    * Description: Constructeur par paramètres
    * Paramètres: - int nb_lignes: nombre de lignes (=nombre de colonne car la matrice est carree)
    *
    * Retour: aucun
    ****************************************************************************/
    template <typename T>
    MCreuse<T>::MCreuse(int nb_lignes)
   {
	   lignes_ = nb_lignes;
	   Indices.resize(boost::extents[lignes_][2]);
	   for(int i=0;i<lignes_;i++)
	   {
		   for(int j=0;j<2;j++)
		   {
			   Indices[i][j]=i;
		   }
		   Values.push_back(1);
	   }   
   }
  /****************************************************************************
    * Fonction: MCreuse<T>::~MCreuse()
    * Description: Destructeur
    * Paramètres: aucun
    * Retour: aucun
    ****************************************************************************/ 
     //template <typename T>
     //MCreuse<T>::~MCreuse()
    //{
		//for(int i=0; i<(Indices.shape()[0]);i++)
		//{
			//extents[(Indices.shape()[0])--][2]);
		//}
		//delete[] Indices;
	    //delete[] Values;
	//}
    /****************************************************************************
    * Fonction: MDense<T>::printIndices()
    * Description: affiche les indices des valeur non nuls de la matrice
    * Paramètres: aucun
    * Retour: aucun
    ****************************************************************************/
    template <typename T>
    void MCreuse<T>::printIndices()
    {
    for(int i=0; i<Indices.shape()[0]; i++)
    {
    for (int j=0; j<Indices.shape()[1]; j++)
    cout<<Indices[i][j]<<" ";
    cout <<" " << endl;
    }
    }
    /****************************************************************************
    * Fonction: MDense<T>::printValues()
    * Description: affiche les valeurs non nuls de la matrice
    * Paramètres: aucun
    * Retour: aucun
    ****************************************************************************/
    template <typename T>
    void MCreuse<T>::printValues()
    {
    for(int i=0; i<Indices.shape()[0]; i++)
    {
		cout<<Values[i]<<endl;
    }
    }
    /****************************************************************************
    * Fonction: MCreuse<T>::AjoutElements()
    * Description: Constructeur par paramètres
    * Paramètres: - T k : valeur a ajouter dans le tableau Values
    *             - int nb_lignes: numero de la ligne correspondante
    *             - int nb-colonnes: numero de la colonne correspondante
    *
    * Retour: aucun
    ****************************************************************************/
    template <typename T>
    void MCreuse<T>::AjoutElements(T k, int i, int j)
    {
		//http://www.developpez.net/forums/d949635/c-cpp/cpp/size-vector-deque-list-seule-dimension/
		Indices.resize(boost::extents[(Indices.shape()[0])+1][2]);
		Indices[(Indices.shape()[0])+1][0]=i;
		Indices[(Indices.shape()[0])+1][1]=j;
		Values.push_back(k);
	}
    /****************************************************************************
    * Fonction : SPMV
    * Description :- calcul le produit matrice_creuse/vecteur et enregistre le temps d'execution et les parametre de la matrice dans un fichier
    *                pour un stockage creux du type COOrdinate, on a une matrice qui contients les indices des valeurs non nuls de la matrice globale
    *                et un tableau qui contient les valeurs non nuls
    * Paramètres : - int **Indices, la matrice d'indices
    *              - T *Values, le tableau de valeurs non nuls
    *              - T *u, le vecteur multiplie
    *              - T *v, le vecteur resultat
    * 			   - int dim la dimension de la matrice
    *              - char* forme, la forme de la matrice
    * Retour: aucun
    ****************************************************************************/
    template <typename T>
    void MCreuse<T>::SPMV(const vector <T>& u, vector <T> v)
    {
		string forme="Stockage COOrdinate";
		//parametres chronometre
		int compteur;
		int f_compteur=1;
		double temps_moy=0.0000; //temps moyen
		
		
			//while(compteur<f_compteur)
			//{//debut chrono
				timer t;
				t.elapsed();
				for(int i=0;i<Indices.shape()[0];i++)
				{
					v[Indices[i][0]]=v[Indices[i][0]]+Values[i]*u[Indices[i][1]];
					//cout<<"pour creuse : v["<<Indices[i][0]<<"]="<<v[Indices[i][0]]<<endl;
				}
				//fin chrono
				temps_moy=temps_moy+t.elapsed();
				//compteur++;
            //}
		    
		    temps_moy = temps_moy/((double)f_compteur);
		    
            // ouverture fichier en ecriture seule
			ofstream fichier("creuse_CPP.csv", ios::out | ios::app);
			if(fichier)
			{
				fichier << lignes_ << ";" << forme << ";" << temps_moy << endl;
				fichier.close();
			}	
		
    }
#endif
